package com.zbkj.service.monitor.channel.hemengyun.request;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zbkj.common.exception.AppException;
import com.zbkj.common.monitorchannel.*;
import com.zbkj.common.monitorchannel.enums.MonitorChannelEnums;
import com.zbkj.common.monitorchannel.vo.*;
import com.zbkj.common.monitorchannel.vo.hemengyun.*;
import com.zbkj.common.utils.RedisUtil;
import com.zbkj.service.monitor.IMonitorChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: HeMengYunMonitor
 * @Description:
 * @Author: fanbing
 * @Date: 2024/6/29 17:31
 * @Version: V1.0
 **/
@Component
@Slf4j
public class HeMengYunMonitorChannel implements IMonitorChannel {

    @Resource
    private RedisUtil redisUtil;

    @Value("${hemengyun.deviceurl}")
    private String device_url;

    @Value("${hemengyun.deviceplayurl}")
    private String DEVICE_PLAYADDR_URL;


    @Value("${hemengyun.url}")
    private String url;

    @Value("${hemengyun.accesskey:G021l7egdug5w4tx}")
    private String accessKey;

    @Value("${hemengyun.accesssecret}")
    private String accessSecret = "";
    private String ENC = "UTF-8";

    @Autowired
    private HeMengYunHelper heMengYunHelper;


    @Autowired
    private HeMengYun3Helper heMengYun3Helper;


    /**
     * v3版本的请求地址
     */
    String DEVICE_V3_URL = "https://gm-cn.smartcloudcon.com";

    @Autowired
    @Qualifier("monitorChannelThreadPool")
    private ThreadPoolTaskExecutor monitorChannelThreadPool;


    @Override
    public MonitorChannelEnums getChannel() {
        return MonitorChannelEnums.HE_MENG_YUN;
    }


    /**
     * 获取流媒体地址
     *
     * @param license
     * @return
     */
    @Override
    public MonitorChannelMediaAddressVo getMediaAddress(String license) {
        String redisKey = "hemengyunplayurlvo_" + license;
        if (redisUtil.exists(redisKey)) {
            String json = redisUtil.get(redisKey);
            MonitorChannelMediaAddressVo mediaAddressVo = JSON.parseObject(json, MonitorChannelMediaAddressVo.class);

            return mediaAddressVo;
        }

        MonitorChannelMediaAddressVo resultMediaAddressVo = new MonitorChannelMediaAddressVo();

        Future<HeMengYunResultVo<HeMengYunPlayUrlVo>> rtspFuture = this.submitRequestMediaAddress(license, "1");
        Future<HeMengYunResultVo<HeMengYunPlayUrlVo>> rtmpFuture = this.submitRequestMediaAddress(license, "2");
        Future<HeMengYunResultVo<HeMengYunPlayUrlVo>> hlsFuture = this.submitRequestMediaAddress(license, "3");
        Future<HeMengYunResultVo<HeMengYunPlayUrlVo>> flvFuture = this.submitRequestMediaAddress(license, "6");

        try {
            resultMediaAddressVo.setRtsp(rtspFuture.get().getData().getPlayURL());
            resultMediaAddressVo.setRmtp(rtmpFuture.get().getData().getPlayURL());
            resultMediaAddressVo.setHls(hlsFuture.get().getData().getPlayURL());
            resultMediaAddressVo.setFlv(flvFuture.get().getData().getPlayURL());
        } catch (Exception e) {
            log.error("HeMengYunMonitorChannel#getMediaAddress获取流媒体地址异常", e);
        }
//        log.info("HeMengYunMonitorChannel#getMediaAddress鹤梦云获取流媒体地址={}", JSON.toJSONString(resultMediaAddressVo));
        redisUtil.set(redisKey, JSON.toJSONString(resultMediaAddressVo), 1L, TimeUnit.MINUTES);
        return resultMediaAddressVo;
    }

    private Future<HeMengYunResultVo<HeMengYunPlayUrlVo>> submitRequestMediaAddress(String license, String proto) {
        JSONObject obj = new JSONObject();
        obj.put("License", license);
        JSONObject Ext = new JSONObject();
        // 媒体的请求协议; 1:RTSP; 2:RTMP; 3:HLS; 4:WebRTC; 6:FLV
        Ext.put("Proto", proto);
        Ext.put("CamID", "0");
        Ext.put("StreamID", "0");
        obj.put("Ext", Ext);
        Callable<HeMengYunResultVo<HeMengYunPlayUrlVo>> task = () -> {
            HeMengYunResultVo getPublicPlayAddr = heMengYunHelper.post("GetPublicPlayAddr", JSONUtil.toJsonStr(obj), DEVICE_PLAYADDR_URL, new HeMengYunResultVo<>());
            HeMengYunResultVo<HeMengYunPlayUrlVo> resultVo = JSON.parseObject(JSON.toJSONString(getPublicPlayAddr), new TypeReference<HeMengYunResultVo<HeMengYunPlayUrlVo>>() {
            });
//            log.info("#submitRequestMediaAddress#proto={};媒体的请求协议:[{}]", proto, resultVo.getData());
            return resultVo;
        };
        return monitorChannelThreadPool.submit(task);
    }

    /**
     * 唤醒设备
     *
     * @param license
     * @return
     */
    @Override
    public boolean wakeUpEquipment(String license) {
//        log.info("#wakeUpEquipment#license唤醒设备=[{}]", license);
        HashMap<String, Object> param = new HashMap<>();
        param.put("License", license);
        HeMengYunResultVo result = heMengYunHelper.post("AwakeDevice", JSONUtil.toJsonStr(param), device_url, new HeMengYunResultVo<>());
//        log.info("#wakeUpEquipment#出参:{}", JSON.toJSON(result));
        if (Objects.equals(result.getCode(), "0")) {
            return Boolean.TRUE;
        }
        throw new AppException(JSON.toJSONString(result));
    }

    /**
     * 获取设备状态
     *
     * @param license
     * @return
     */
    @Override
    public MonitorChannelEquipmentStatusVo getEquipmentStatus(String license) {
        HashMap<String, Object> requestVo = Maps.newHashMap();
        requestVo.put("License", license);
        HeMengYunResultVo<MonitorChannelEquipmentStatusVo> result = heMengYunHelper.post("QueryDeviceStatus", JSONUtil.toJsonStr(requestVo), device_url, new HeMengYunResultVo<MonitorChannelEquipmentStatusVo>());
        String jsonString = JSON.toJSONString(result);
//        log.info("HeMengYunMonitor#getEquipmentStatus鹤梦云获取设备状态:{}", jsonString);
        HeMengYunResultVo<MonitorChannelEquipmentStatusVo> resultVo = JSON.parseObject(jsonString, new TypeReference<HeMengYunResultVo<MonitorChannelEquipmentStatusVo>>() {
        });

        return resultVo.getData();
    }


    @Override
    public boolean ctrlPTZ(CtrlPTZRequestVo ctrlPTZRequestVo) {
        HeMengYunCtrlPTZRequestVo ptzRequestVo = new HeMengYunCtrlPTZRequestVo();
        ptzRequestVo.setPTZType(ctrlPTZRequestVo.getPtzType());
        ptzRequestVo.setPTZControl(ctrlPTZRequestVo.getPtzControl());
        ptzRequestVo.setSpeed(ctrlPTZRequestVo.getSpeed());
        ptzRequestVo.setStep(ctrlPTZRequestVo.getStep());

        HeMengYunBaseRequestVo<HeMengYunCtrlPTZRequestVo> requestVo = new HeMengYunBaseRequestVo<>();
        requestVo.setLicense(ctrlPTZRequestVo.getLicense());
        requestVo.setBODY(ptzRequestVo);
        HeMengYunResultVo result = heMengYunHelper.post("CtrlPTZ", JSONUtil.toJsonStr(requestVo), device_url, new HeMengYunResultVo<>());

        if (Objects.equals(result.getCode(), "0")) {
            return Boolean.TRUE;
        }
        throw new AppException(JSON.toJSONString(result));
    }


    /**
     * 通过该命令向设备设置时间信息
     *
     * @param setTimeRequestVo
     * @return
     */
    @Override
    public boolean setTime(MonitorSetTimeRequestVo setTimeRequestVo) {
        HeMengYunSetTimeRequestVo tzRequestVo = new HeMengYunSetTimeRequestVo();
        tzRequestVo.setTime(setTimeRequestVo.getTime());
        tzRequestVo.setSyncFlag(setTimeRequestVo.getSyncFlag());
        tzRequestVo.setZone(setTimeRequestVo.getZone());
        tzRequestVo.setDstUseFlag(setTimeRequestVo.getDstUseFlag());
        tzRequestVo.setArea(setTimeRequestVo.getArea());
        tzRequestVo.setTimeMode(setTimeRequestVo.getTimeMode());

        HeMengYunBaseRequestVo<HeMengYunSetTimeRequestVo> requestVo = new HeMengYunBaseRequestVo<>();
        requestVo.setLicense(setTimeRequestVo.getLicense());
        requestVo.setBODY(tzRequestVo);
        HeMengYunResultVo result = heMengYunHelper.post("SetTime", JSONUtil.toJsonStr(requestVo), device_url, new HeMengYunResultVo<>());

        if (Objects.equals(result.getCode(), "0")) {
            return Boolean.TRUE;
        }
        throw new AppException(JSON.toJSONString(result));
    }


    /**
     * 通知设备进⾏行行物理理变焦
     * 鹤梦云-2.6.2.8.6 通知设备进⾏行行物理理变焦
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo setAdjustFocalLength(AdjustFocalLengthRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        Map<String, Object> body = Maps.newHashMap();
        body.put("LenID", requestVo.getLenID());
        body.put("CtrlType", requestVo.getCtrlType());
        body.put("Derection", requestVo.getCtrlType());
        param.put("BODY", body);

        HeMengYunResultVo result = heMengYunHelper.post("AdjustFocalLength", JSONUtil.toJsonStr(param), device_url, new HeMengYunResultVo<>());

        ThirdMonitorResultVo resultVo = JSON.parseObject(JSON.toJSONString(result), ThirdMonitorResultVo.class);
        return resultVo;
    }


    /**
     * 通知设备抓图
     * 鹤梦云-4.6.2.2.8 通知设备抓图
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo noticeDeviceUploadPicRequest(NoticeDeviceUploadPicRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        Map<String, Object> body = Maps.newHashMap();
        body.put("PicType", requestVo.getPicType());
        body.put("GifFlag", requestVo.getGifFlag());
        NoticeDeviceUploadPicThirdInfoRequestVo thirdInfo = requestVo.getThirdInfo();
        if (ObjectUtil.isNull(requestVo.getThirdInfo()) || StrUtil.isBlank(thirdInfo.getDate())) {
            thirdInfo = new NoticeDeviceUploadPicThirdInfoRequestVo();
            thirdInfo.setDate(DateUtil.formatDate(new Date()));
        }

        body.put("ThirdInfo", JSON.toJSONString(thirdInfo));
        body.put("WorkType", requestVo.getWorkType());
        param.put("BODY", body);

        HeMengYunResultVo result = heMengYunHelper.post("NoticeDeviceUploadPic", JSONUtil.toJsonStr(param), device_url, new HeMengYunResultVo<>());

        ThirdMonitorResultVo resultVo = JSON.parseObject(JSON.toJSONString(result), ThirdMonitorResultVo.class);
        return resultVo;
    }


    /**
     * 查询设备云端录像⽇日历
     * 4.6.2.3.1 查询设备云端录像⽇日历
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<VideoQueryCalendarResultVo> getVideoQueryCalendar(VideoQueryCalendarRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        param.put("Date", requestVo.getDate());
        String requestUrl = url + "/APIIn/Video";

        HeMengYunResultVo result = heMengYunHelper.post("QueryCalendar", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<VideoQueryCalendarResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<VideoQueryCalendarResultVo>>() {
        });
        return resultVo;
    }


    /**
     * 查询设备云端录像列列表
     * 4.6.2.3.2 查询设备云端录像列列表
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<VideoQueryListResultVo> getVideoQueryList(VideoQueryListRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        param.put("Date", requestVo.getDate());
        if (StrUtil.isNotBlank(requestVo.getPageSize())) {
            param.put("PageSize", requestVo.getPageSize());
        }
        String requestUrl = url + "/APIIn/Video";

        HeMengYunResultVo result = heMengYunHelper.post("QueryList", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<VideoQueryListResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<VideoQueryListResultVo>>() {
        });
        return resultVo;
    }


    /**
     * 查询设备云端录像详情
     * 4.6.2.3.3 查询设备云端录像详情
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<VideoQueryDetailResultVo> getVideoQueryDetail(VideoQueryDetailRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        param.put("FileID", requestVo.getFileID());
        String requestUrl = url + "/APIIn/Video";

        HeMengYunResultVo result = heMengYunHelper.post("QueryDetail", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<VideoQueryDetailResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<VideoQueryDetailResultVo>>() {
        });
        return resultVo;
    }


    /**
     * 查询设备云端图⽚片列列表
     * 4.6.2.2.2 查询设备云端图⽚片列列表
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<PictureQueryListResultVo> getPictureQueryList(VideoQueryListRequestVo requestVo) {

        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        param.put("Date", requestVo.getDate());
        if (StrUtil.isNotBlank(requestVo.getPageSize())) {
            param.put("PageSize", requestVo.getPageSize());
        }
        String requestUrl = url + "/APIIn/Picture";

        HeMengYunResultVo result = heMengYunHelper.post("QueryList", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<PictureQueryListResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<PictureQueryListResultVo>>() {
        });
        return resultVo;
    }


    /**
     * 查询设备云端图⽚片详情
     * 4.6.2.2.3 查询设备云端图⽚片详情
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<PictureQueryDetailResultVo> getPictureQueryDetail(PictureQueryDetailRequestVo requestVo) {

        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        param.put("FileID", requestVo.getFileID());
        String requestUrl = url + "/APIIn/Picture";

        HeMengYunResultVo result = heMengYunHelper.post("QueryDetail", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<PictureQueryDetailResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<PictureQueryDetailResultVo>>() {
        });

        return resultVo;
    }

    /**
     * 查询设备云端图⽚片详情
     * 鹤梦云-4.6.2.2.7 查询设备本地图⽚片列列表(须设备在线才可查询)
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<GetLocalPicListResultVo> getGetLocalPicList(VideoQueryListRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        Map<String, Object> body = Maps.newHashMap();
        body.put("Date", requestVo.getDate());
        body.put("PageSize", requestVo.getPageSize());
        param.put("BODY", body);

        String requestUrl = url + "/APIIn/Device";

        HeMengYunResultVo result = heMengYunHelper.post("GetLocalPicList", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<GetLocalPicListResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<GetLocalPicListResultVo>>() {
        });

        return resultVo;
    }

    /**
     * 查询设备本地录像列列表
     * 鹤梦云-4.6.2.3.5 查询设备本地录像列列表
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<GetLocalFileListResultVo> getLocalFileList(GetLocalFileListRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        Map<String, Object> body = Maps.newHashMap();
        body.put("Date", requestVo.getDate());
        body.put("PageSize", requestVo.getPageSize());
        param.put("BODY", body);

        String requestUrl = url + "/APIIn/Device";

        HeMengYunResultVo result = heMengYunHelper.post("GetLocalFileList", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<GetLocalFileListResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<GetLocalFileListResultVo>>() {
        });

        return resultVo;
    }

    /**
     * 鹤梦云-4.6.2.2.5 根据事件时间查询设备云端图⽚片详情
     */
    @Override
    public ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo> QueryDetailByTime(QueryDetailByTimeRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        param.put("Time", requestVo.getTime());

        String requestUrl = url + "/APIIn/Picture";

        HeMengYunResultVo result = heMengYunHelper.post("QueryDetailByTime", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo>>() {
        });
        return resultVo;
    }


    /**
     * 4.5.1 根据产品ID进⾏行行订阅数据
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo subscribe(MonitorSubscribeRequestVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getLicense())) {
            param.put("License", requestVo.getLicense());
        }
        if (StrUtil.isNotBlank(requestVo.getProductId())) {
            param.put("ProductID", requestVo.getProductId());
        }
        param.put("Status", requestVo.getStatus());
        param.put("Topic", requestVo.getTopic());

        String requestUrl = url + "/APIIn/Subscribe";

        HeMengYunResultVo result = heMengYunHelper.post("Product", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo>>() {
        });
        return resultVo;
    }


    /**
     * 4.6.2.6.3 摄像头开关
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo setOpenFlag(MonitorSetOpenFlagVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        Map<String, Object> body = Maps.newHashMap();
        body.put("Status", requestVo.getStatus());
        param.put("BODY", body);

        String requestUrl = url + "/APIIn/Device";

        HeMengYunResultVo result = heMengYunHelper.post("SetOpenFlag", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo>>() {
        });
        return resultVo;

    }

    /**
     * 4.6.2.3.4 查询设备本地录像⽇日历
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo getLocalFileCalendar(GetLocalFileCalendarVo requestVo) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("License", requestVo.getLicense());
        Map<String, Object> body = Maps.newHashMap();
        body.put("Date", requestVo.getDate());
        param.put("BODY", body);

        String requestUrl = url + "/APIIn/Device";

        HeMengYunResultVo result = heMengYunHelper.post("GetLocalFileCalendar", JSONUtil.toJsonStr(param), requestUrl, new HeMengYunResultVo<>());
        ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo> resultVo = JSON.parseObject(JSON.toJSONString(result), new TypeReference<ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo>>() {
        });
        return resultVo;
    }


    /**
     * 获取v3版本的 accessToken
     *
     * @return
     */
    @Override
    public String getV3AccessToken() {

      /*  String redisKey = "hemengyun_accessToken";
        String accessToken = redisUtil.get(redisKey);
        if (StrUtil.isNotBlank(accessToken)) {
            return accessToken;
        }*/

        Map map = Maps.newHashMap();
        map.put("AccessKey", accessKey);
        map.put("AccessSecret", accessSecret);
        String data = JSON.toJSONString(map);
        HeMengYunV3AccessTokenResultVo accessTokenResultVo = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/GenPlatformAccessToken", "", data, new TypeReference<HeMengYunV3AccessTokenResultVo>() {
        });
        if (ObjectUtil.isNull(accessTokenResultVo) || StrUtil.isBlank(accessTokenResultVo.getAccessToken())) {
            throw new AppException("鹤梦云PaaS能力平台V3获取accessToken失败");
        }
//        Long AccessTokenExpires = Long.valueOf(accessTokenResultVo.getAccessTokenExpires());
//        redisUtil.set(redisKey, accessTokenResultVo.getAccessToken(), AccessTokenExpires - 1000);

        return accessTokenResultVo.getAccessToken();
    }

    /**
     * 5.5.8.2 获取 TF 录像回放地址标准流地址
     * 功能说明：
     * 1、获取设备流媒体录像回放地址；
     * 2、请求路径 url: /GMModule/V3/Media/GetMultiMediaRecordAddr；
     *
     * @param requestVo
     * @return
     */
    public GetMultiMediaRecordAddrV3Response GetMultiMediaRecordAddr(GetMultiMediaRecordAddrV3Request requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        param.put("DID", requestVo.getDid());
        if (StrUtil.isNotBlank(requestVo.getProto())) {
            param.put("Proto", requestVo.getProto());
        }
        if (StrUtil.isNotBlank(requestVo.getCamID())) {
            param.put("CamID", requestVo.getCamID());
        }
        if (StrUtil.isNotBlank(requestVo.getOfferSDP())) {
            param.put("OfferSDP", requestVo.getOfferSDP());
        }
        if (StrUtil.isNotBlank(requestVo.getStartTime())) {
            param.put("StartTime", requestVo.getStartTime());
        }
        if (StrUtil.isNotBlank(requestVo.getSpeed())) {
            param.put("Speed", requestVo.getSpeed());
        }


        GetMultiMediaRecordAddrV3Response response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Media/GetMultiMediaRecordAddr", v3AccessToken, JSON.toJSONString(param), new TypeReference<GetMultiMediaRecordAddrV3Response>() {
        });

        return response;
    }


    /**
     * 5.5.3.2 查询 TF 卡录像列表
     * 功能说明：
     * 1、按照日期查询 TF 卡录像列表；
     * 2、请求 URL；/GMModule/V3/Device/GetLocalFileList；
     *
     * @param requestVo
     * @return
     */
    public GetLocalFileListV3Response GetLocalFileList(GetLocalFileListV3Request requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        param.put("DID", requestVo.getDid());
        param.put("Date", requestVo.getDate());
        param.put("PageSize", requestVo.getPageSize());
        GetLocalFileListV3Response response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/GetLocalFileList", v3AccessToken, JSON.toJSONString(param), new TypeReference<GetLocalFileListV3Response>() {
        });

        return response;
    }


    /**
     * 5.5.3.3 查询 TF 卡事件日历
     * 功能说明：
     * 1、查询 TF 卡那天存在报警事件；
     * 2、请求 URL；/GMModule/V3/Device/GetLocalEventCalendar
     *
     * @param requestVo
     * @return
     */
    public GetLocalEventCalendarV3Response GetLocalEventCalendar(GetLocalEventCalendarV3Request requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        param.put("DID", requestVo.getDid());
        param.put("Date", requestVo.getDate());
        GetLocalEventCalendarV3Response response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/GetLocalEventCalendar", v3AccessToken, JSON.toJSONString(param), new TypeReference<GetLocalEventCalendarV3Response>() {
        });

        return response;
    }

    /**
     * 5.2.2 用户账号添加/删除设备
     * 功能说明：
     * 1、用户添加或者删除设备；
     * 2、该接口影响用户对设备的所有操作;
     * 3、请求路径 url: /GMModule/SetDevices;
     *
     * @param requestVo
     * @return
     */
    public SetDevicesV3Response SetDevices(SetDevicesV3Request requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getSetCmd())) {
            param.put("SetCmd", requestVo.getSetCmd());
        }
        if (StrUtil.isNotBlank(requestVo.getCompanyID())) {
            param.put("CompanyID", requestVo.getCompanyID());
        }
        if (StrUtil.isNotBlank(requestVo.getAccountID())) {
            param.put("AccountID", requestVo.getAccountID());
        }
        if (!CollectionUtils.isEmpty(requestVo.getLicenseList())) {
            param.put("LicenseList", requestVo.getLicenseList());
        }
        SetDevicesV3Response response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/SetDevices", v3AccessToken, JSON.toJSONString(param), new TypeReference<SetDevicesV3Response>() {
        });

        return response;
    }

    /**
     * 5.5.1.1 查询设备的业务配置
     * 功能说明：
     * 1、根据功能模块类型查询设备的配置和能力；
     * 2、请求 URL；/GMModule/V3/Device/GetDeviceModel;
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject GetDeviceModel(GetDeviceModelV3Request requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        if (StrUtil.isNotBlank(requestVo.getLanguage())) {
            param.put("Language", requestVo.getLanguage());
        }
        List<Map<String, Object>> modules = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(requestVo.getModules())) {
            for (GetDeviceModelModulesV3Request request : requestVo.getModules()) {
                Map<String, Object> map = Maps.newHashMap();
                map.put("AIIoTType", request.getAIIoTType());
                map.put("AIIoTID", request.getAIIoTID());
                modules.add(map);
            }

        }

        param.put("Modules", modules);
        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/GetDeviceModel", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;
    }


    /**
     * 5.5.8.1 获取直播播放地址
     * 功能说明：
     * 1、获取设备流媒体直播地址；
     * 2、请求路径 url: /GMModule/V3/Media/GetMultiMediaAddr；
     *
     * @param requestVo
     * @return
     */
    @Override
    public GetMultiMediaAddrV3Response GetMultiMediaAddr(GetMultiMediaAddrV3Request requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        if (StrUtil.isNotBlank(requestVo.getProto())) {
            param.put("Proto", requestVo.getProto());
        }
        if (StrUtil.isNotBlank(requestVo.getCamID())) {
            param.put("CamID", requestVo.getCamID());
        }
        if (StrUtil.isNotBlank(requestVo.getStreamID())) {
            param.put("StreamID", requestVo.getStreamID());
        }
        if (StrUtil.isNotBlank(requestVo.getOfferSDP())) {
            param.put("OfferSDP", requestVo.getOfferSDP());
        }
        GetMultiMediaAddrV3Response response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Media/GetMultiMediaAddr", v3AccessToken, JSON.toJSONString(param), new TypeReference<GetMultiMediaAddrV3Response>() {
        });

        return response;
    }


    /**
     * 5.5.8.2获取TF录像回放地址标准流地址
     * 1、获取设备流媒体录像回放地址；
     * 2、请求路径url:/GMModule/V3/Media/GetMultiMediaRecordAddr
     *
     * @param requestVo
     * @return
     */
    @Override
    public GetMultiMediaAddrV3Response GetMultiMediaRecordV3Request(GetMultiMediaRecordV3Request requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        if (StrUtil.isNotBlank(requestVo.getProto())) {
            param.put("Proto", requestVo.getProto());
        }
        if (StrUtil.isNotBlank(requestVo.getCamID())) {
            param.put("CamID", requestVo.getCamID());
        }
        if (StrUtil.isNotBlank(requestVo.getOfferSDP())) {
            param.put("OfferSDP", requestVo.getOfferSDP());
        }
        if (StrUtil.isNotBlank(requestVo.getStartTime())) {
            param.put("StartTime", requestVo.getStartTime());
        }
        if (StrUtil.isNotBlank(requestVo.getSpeed())) {
            param.put("Speed", requestVo.getSpeed());
        }
        GetMultiMediaAddrV3Response response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Media/GetMultiMediaRecordAddr", v3AccessToken, JSON.toJSONString(param), new TypeReference<GetMultiMediaAddrV3Response>() {
        });

        return response;
    }


    /**
     * 5.5.4.7 摄像机开关
     * 功能说明：
     * 1、关闭摄像机后，停止所有录制，同时app默认不可以观看，同时镜头转向隐私位；
     * 2、请求URL；/GMModule/V3/Device/SetOpenFlag
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3SetOpenFlag(MonitorSetOpenFlagVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        if (StrUtil.isNotBlank(requestVo.getStatus())) {
            param.put("Status", requestVo.getStatus());
        }
        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/SetOpenFlag", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;
    }
    /**
     * 5.5.4.2 重启设备
     * 功能说明：
     * 1、重启设备；
     * 2、请求URL；/GMModule/V3/Device/RebootDevice
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3RebootDevice(MonitorRebootDeviceVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        if (StrUtil.isNotBlank(requestVo.getSilentFlag())) {
            param.put("SilentFlag", requestVo.getSilentFlag());
        }
        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/RebootDevice", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;

    }


    /**
     * 5.5.4.3 检测设备版本是否可升级
     * 功能说明：
     * 1、后台比较设备当前版本号与后台版本号，当后台版本呢大于当前版本，则可升级；
     * 比较方式：strcmp("当前版本号","后台版本号") > 0 ；
     * 2、请求 URL；；/GMModule/V3/Device/CheckDeviceUpgradeVersion
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3CheckDeviceUpgradeVersion(MonitorBaseVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/CheckDeviceUpgradeVersion", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;

    }


    /**
     * 5.5.4.4 通知设备升级到最新版本
     * 功能说明：
     * 1、当检测设备有新版后，通知设备进行 OTA；
     * 2、请求 URL；/GMModule/V3/Device/NoticeUpgradeDeviceToLatestVersion
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3NoticeUpgradeDeviceToLatestVersion(MonitorBaseVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/NoticeUpgradeDeviceToLatestVersion", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;

    }


    /**
     * 5.5.4.17 获取 TF 卡信息
     * 功能说明：
     * 1、查询 TF 卡的容量信息；
     * 2、请求 URL；/GMModule/V3/Device/GetSDCardInfo
     *
     * @param requestVo
     * @return
     */
    @Override
    public MonitorGetSDCardInfoResultVo v3GetSDCardInfo(MonitorBaseVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        MonitorGetSDCardInfoResultVo response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/GetSDCardInfo", v3AccessToken, JSON.toJSONString(param), new TypeReference<MonitorGetSDCardInfoResultVo>() {
        });

        return response;

    }

    /**
     * 5.5.4.18 格式化 TF 卡
     * 功能说明：
     * 1、格式话设备 TF 卡，TF 卡数据将会全部丢失；
     * 2、请求 URL；/GMModule/V3/Device/FormatSDCard
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3FormatSDCard(MonitorBaseVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/FormatSDCard", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;

    }
    /**
     * 5.5.4.19 设置设备名称
     * 功能说明：
     * 1、修改设备的名称；
     * 2、请求 URL；/GMModule/V3/Device/SetDeviceName
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3SetDeviceName(MonitorSetDeviceNameVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        if (StrUtil.isNotBlank(requestVo.getDevName())) {
            param.put("DevName", requestVo.getDevName());
        }
        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/SetDeviceName", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;

    }
    /**
     * 5.5.4.26 控制设备进行放大和缩小
     * 功能说明：
     * 1、当设备具有变焦能力的时候，通过该接口通知设备变焦，可以是电子变焦或光学变
     * 焦；
     * 2、请求 URL；/GMModule/V3/Device/AdjustFocalLength
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3AdjustFocalLength(MonitorAdjustFocalLengthVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        if (StrUtil.isNotBlank(requestVo.getCamID())) {
            param.put("CamID", requestVo.getCamID());
        }
        if (StrUtil.isNotBlank(requestVo.getCtrlType())) {
            param.put("CtrlType", requestVo.getCtrlType());
        }
        if (StrUtil.isNotBlank(requestVo.getDerection())) {
            param.put("Derection", requestVo.getDerection());
        }
        if (StrUtil.isNotBlank(requestVo.getZoomValue())) {
            param.put("ZoomValue", requestVo.getZoomValue());
        }

        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/AdjustFocalLength", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;

    }


    /**
     * 5.5.4.27 设置电池工作模式
     * 功能说明：
     * 1、设置电池摄像机的工作模式，前提是设备支持工作模式切换；
     * 2、请求 URL；/GMModule/V3/Device/SetBatteryWorkMode
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3SetBatteryWorkMode(MonitorSetBatteryWorkModeVo requestVo) {
        String v3AccessToken = this.getV3AccessToken();

        Map<String, Object> param = Maps.newHashMap();
        if (StrUtil.isNotBlank(requestVo.getDid())) {
            param.put("DID", requestVo.getDid());
        }
        if (StrUtil.isNotBlank(requestVo.getWorkType())) {
            param.put("WorkType", requestVo.getWorkType());
        }
        if (StrUtil.isNotBlank(requestVo.getModeId())) {
            param.put("ModeId", requestVo.getModeId());
        }

        JSONObject response = heMengYun3Helper.post(DEVICE_V3_URL, "/GMModule/V3/Device/SetBatteryWorkMode", v3AccessToken, JSON.toJSONString(param), new TypeReference<JSONObject>() {
        });

        return response;

    }
}
